home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / c / stdio / vfprintf.c < prev    next >
C/C++ Source or Header  |  1992-03-27  |  22KB  |  962 lines

  1. /* 
  2.  * vfprintf.c --
  3.  *
  4.  *    Source code for the "vfprintf" library procedure.
  5.  *
  6.  * Copyright 1988 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/lib/c/stdio/RCS/vfprintf.c,v 1.20 91/08/27 17:35:55 rab Exp Locker: rab $ SPRITE (Berkeley)";
  18. #endif not lint
  19.  
  20. #include <ctype.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <varargs.h>
  25. #include <math.h>
  26.  
  27. extern int signbit _ARGS_ ((int value));
  28.  
  29. #ifndef TRUE
  30. #define TRUE 1
  31. #endif
  32. #ifndef FALSE
  33. #define FALSE 0
  34. #endif
  35.  
  36. /*
  37.  * The following defines the size of buffer needed to hold the ASCII
  38.  * digits for the largest floating-point number and the largest integer.
  39.  */
  40.  
  41. #define CVT_DBL_BUF_SIZE 320
  42. #define CVT_INT_BUF_SIZE 33
  43.  
  44. /*
  45.  *----------------------------------------------------------------------
  46.  *
  47.  * CvtUtoA --
  48.  *
  49.  *    Convert a number from internal form to a sequence of
  50.  *    ASCII digits.
  51.  *
  52.  * Results:
  53.  *    The return value is a pointer to the ASCII digits representing
  54.  *    i, and *lengthPtr will be filled in with the number of digits
  55.  *    stored at the location pointed to by the return value.  The
  56.  *    return value points somewhere inside buf, but not necessarily
  57.  *    to the beginning.  Note:  the digits are left null-terminated.
  58.  *
  59.  * Side effects:
  60.  *    None.
  61.  *
  62.  *----------------------------------------------------------------------
  63.  */
  64.  
  65. static char *
  66. CvtUtoA(i, base, buf, lengthPtr, capsFlag)
  67.     register unsigned i;    /* Value to convert. */
  68.     register int base;        /* Base for conversion.  Shouldn't be
  69.                  * larger than 36.  2, 8, and 16
  70.                  * execute fastest.
  71.                  */
  72.     register char *buf;        /* Buffer to use to hold converted string.
  73.                  * Must hold at least CVT_INT_BUF_SIZE bytes. */
  74.     int *lengthPtr;        /* Number of digits is stored here. */
  75.     int capsFlag;        /* 1 if want capital abcd... */
  76. {
  77.     register char *p;
  78.     register char hexOffset = (capsFlag ? 'A': 'a')-'9'-1;
  79.  
  80.     /*
  81.      * Handle a zero value specially.
  82.      */
  83.  
  84.     if (i == 0) {
  85.     buf[0] = '0';
  86.     buf[1] = 0;
  87.     *lengthPtr = 1;
  88.     return buf;
  89.     }
  90.  
  91.     /*
  92.      * Build the string backwards from the end of the result array.
  93.      */
  94.  
  95.     p = &buf[CVT_INT_BUF_SIZE-1];
  96.     *p = 0;
  97.  
  98.     switch (base) {
  99.  
  100.     case 2:
  101.         while (i != 0) {
  102.         p -= 1;
  103.         *p = '0' + (i & 01);
  104.         i >>= 1;
  105.         }
  106.         break;
  107.     
  108.     case 8:
  109.         while (i != 0) {
  110.         p -= 1;
  111.         *p = '0' + (i & 07);
  112.         i >>= 3;
  113.         }
  114.         break;
  115.     
  116.     case 16:
  117.         while (i !=0) {
  118.         p -= 1;
  119.         *p = '0' + (i & 0xf);
  120.         if (*p > '9') {
  121.             *p += hexOffset;
  122.         }
  123.         i >>= 4;
  124.         }
  125.         break;
  126.     
  127.     default:
  128.         while (i != 0) {
  129.         p -= 1;
  130.         *p = '0' + (i % base);
  131.         if (*p > '9') {
  132.             *p += hexOffset;
  133.         }
  134.         i /= base;
  135.         }
  136.         break;
  137.     }
  138.  
  139.     *lengthPtr = (&buf[CVT_INT_BUF_SIZE-1] - p);
  140.     return p;
  141. }
  142.  
  143. /*
  144.  *----------------------------------------------------------------------
  145.  *
  146.  * CvtFtoA --
  147.  *
  148.  *    This procedure converts a double-precision floating-point
  149.  *    number to a string of ASCII digits.
  150.  *
  151.  * Results:
  152.  *    The characters at buf are modified to hold up to numDigits ASCII
  153.  *    characters, followed by a null character.  The digits represent
  154.  *    the most significant numDigits digits of value, with the lowest
  155.  *    digit rounded.  The value at *pointPtr is modified to hold
  156.  *    the number of characters in buf that precede the decimal point.
  157.  *    A negative value of *pointPtr means zeroes must be inserted
  158.  *    between the point and buf[0].  If value is negative, *signPtr
  159.  *    is set to TRUE;    otherwise it is set to FALSE.  The return value
  160.  *    is the number of digits stored in buf, which is either:
  161.  *    (a) numDigits (if the number is so huge that all numDigits places are
  162.  *        used before getting to the right precision level, or if
  163.  *        afterPoint is -1)
  164.  *    (b) afterPoint + *pointPtr (the normal case if afterPoint isn't -1)
  165.  *    If there were no significant digits within the specified precision,
  166.  *    then *pointPtr gets set to -afterPoint and 0 is returned.
  167.  *
  168.  * Side effects:
  169.  *    None.
  170.  *
  171.  *----------------------------------------------------------------------
  172.  */
  173.  
  174. static int
  175. CvtFtoA(value, numDigits, afterPoint, pointPtr, signPtr, buf, fpError)
  176.     double value;        /* Value to be converted. */
  177.     int numDigits;        /* Maximum number of significant digits
  178.                  * to generate in result. */
  179.     int afterPoint;        /* Maximum number of digits to generate
  180.                  * after the decimal point.  If -1, then
  181.                  * there there is no limit. */
  182.     int *pointPtr;        /* Will be filled in with position of
  183.                  * decimal point (number of digits before
  184.                  * decimal point). */
  185.     int *signPtr;        /* Modified to indicate whether or not
  186.                  * value was negative. */
  187.     char *buf;            /* Place to store ASCII digits.  Must hold
  188.                  * at least numDigits+1 bytes. */
  189.     int *fpError;               /* pointer to flag that is set if the number
  190.                                    is not a valid number. */
  191.  
  192. {
  193.     register char *p;
  194.     double fraction, intPart;
  195.     int i, numDigits2;
  196.     char tmpBuf[CVT_DBL_BUF_SIZE];
  197.                 /* Large enough to hold largest possible
  198.                  * floating-point number.
  199.                  */
  200.  
  201.     /*
  202.      * Take care of the sign.
  203.      */
  204.  
  205.     if (signbit(value)) {
  206.     *signPtr = TRUE;
  207.     value = -value;
  208.     } else {
  209.     *signPtr = FALSE;
  210.     }
  211.  
  212.     /*
  213.      * Make sure the value is a valid number
  214.      */
  215.     if (isinf(value)) {
  216.     /*
  217.      * Set the error flag so the invoking function will know
  218.      * that something is wrong.
  219.      */
  220.     *fpError = TRUE;
  221.     strcpy(buf, "Inf");
  222.     return sizeof("Inf") - 1;
  223.     }
  224.     if (isnan(value)) {
  225.     *fpError = TRUE;
  226.     strcpy(buf, "NaN");
  227.     return sizeof("NaN") - 1;
  228.     }
  229.  
  230.     *fpError = FALSE;
  231.  
  232.     /*
  233.      * Divide value into an integer and a fractional component.  Convert
  234.      * the integer to ASCII in a temporary buffer, then move the characters
  235.      * to the real buffer (since we're converting from the bottom up,
  236.      * we won't know the highest-order digit until last).
  237.      */
  238.  
  239.     fraction = modf(value, &intPart);
  240.     *pointPtr = 0;
  241.     for (p = &tmpBuf[CVT_DBL_BUF_SIZE-1]; intPart != 0; p -= 1) {
  242.     double tmp;
  243.     char digit;
  244.  
  245.     tmp = modf(intPart/10.0, &intPart);
  246.  
  247.     digit = (tmp * 10.0) + .2;
  248.     *p = digit + '0';
  249.     *pointPtr += 1;
  250.     }
  251.     p++;
  252.     for (i = 0; (i <= numDigits) && (p <= &tmpBuf[CVT_DBL_BUF_SIZE-1]);
  253.         i++, p++) {
  254.     buf[i] = *p;
  255.     }
  256.  
  257.     /*
  258.      * If the value was zero, put an initial zero in the buffer
  259.      * before the decimal point.
  260.      */
  261.     
  262.     if (value == 0.0) {
  263.     buf[0] = '0';
  264.     i = 1;
  265.     *pointPtr = 1;
  266.     }
  267.  
  268.     /*
  269.      * Now handle the fractional part that's left.  Repeatedly multiply
  270.      * by 10 to get the next digit.  At the beginning, the value may be
  271.      * very small, so do repeated multiplications until we get to a
  272.      * significant digit.
  273.      */
  274.     
  275.     if ((i == 0) && (fraction > 0)) {
  276.     while (fraction < .1) {
  277.         fraction *= 10.0;
  278.         *pointPtr -= 1;
  279.     };
  280.     }
  281.  
  282.     /*
  283.      * Compute how many total digits we should generate, taking into
  284.      * account both numDigits and afterPoint.  Then generate the digits.
  285.      */
  286.     
  287.     numDigits2 = afterPoint + *pointPtr;
  288.     if ((afterPoint < 0) || (numDigits2 > numDigits)) {
  289.     numDigits2 = numDigits;
  290.     }
  291.     
  292.     for ( ; i <= numDigits2; i++) {
  293.     double tmp;
  294.     char digit;
  295.  
  296.     fraction = modf(fraction*10.0, &tmp);
  297.  
  298.     digit = tmp;
  299.     buf[i] = digit + '0';
  300.     }
  301.  
  302.     /*
  303.      * The code above actually computed one more digit than is really
  304.      * needed.  Use it to round the low-order significant digit, if
  305.      * necessary.  This could cause rounding to propagate all the way
  306.      * back through the number.
  307.      */
  308.     
  309.     if ((numDigits2 >= 0) && (buf[numDigits2] >= '5')) {
  310.     for (i = numDigits2-1; ; i--) {
  311.         if (i < 0) {
  312.         int j;
  313.  
  314.         /*
  315.          * Must slide the entire buffer down one slot to make
  316.          * room for a leading 1 in the buffer.  Careful: if we've
  317.          * already got numDigits digits, must drop the last one to
  318.          * add the 1.
  319.          */
  320.  
  321.         for (j = numDigits2; j > 0; j--) {
  322.             buf[j] = buf[j-1];
  323.         }
  324.         if (numDigits2 < numDigits) {
  325.             numDigits2++;
  326.         }
  327.         (*pointPtr)++;
  328.         buf[0] = '1';
  329.         break;
  330.         }
  331.  
  332.         buf[i] += 1;
  333.         if (buf[i] <= '9') {
  334.         break;
  335.         }
  336.         buf[i] = '0';
  337.     }
  338.     }
  339.  
  340.     if (numDigits2 <= 0) {
  341.     numDigits2 = 0;
  342.     *pointPtr = -afterPoint;
  343.     }
  344.     buf[numDigits2] = 0;
  345.     return numDigits2;
  346. }
  347.  
  348. /*
  349.  *----------------------------------------------------------------------
  350.  *
  351.  * vfprintf --
  352.  *
  353.  *    This utility routine does all of the real work of printing
  354.  *    formatted information.  It is called by printf, fprintf,
  355.  *    sprintf, vprintf, and vsprintf.
  356.  *
  357.  * Results:
  358.  *    The return value is the total number of characters printed.
  359.  *
  360.  * Side effects:
  361.  *    Information is output on stream.  See the manual page entry
  362.  *    for printf for details.
  363.  *
  364.  *----------------------------------------------------------------------
  365.  */
  366.  
  367. int
  368. vfprintf(stream, format, args)
  369.     register FILE *stream;    /* Where to output formatted results. */
  370.     register char *format;    /* Contains literal text and format control
  371.                  * sequences indicating how args are to be
  372.                  * printed.  See the man page for details. */
  373.     va_list args;        /* Variable number of values to be formatted
  374.                  * and printed. */
  375. {
  376.     int leftAdjust;        /* TRUE means field should be left-adjusted. */
  377.     int minWidth;        /* Minimum width of field. */
  378.     int precision;        /* Precision for field (e.g. digits after
  379.                  * decimal, or string length). */
  380.     int altForm;        /* TRUE means value should be converted to
  381.                  * an alternate form (depends on type of
  382.                  * conversion). */
  383.     register char c;        /* Current character from format string.
  384.                  * Eventually it ends up holding the format
  385.                  * type (e.g. 'd' for decimal). */
  386.     char pad;            /* Pad character. */
  387.     char buf[CVT_DBL_BUF_SIZE+10];
  388.                 /* Buffer used to hold converted numbers
  389.                  * before outputting to stream.  Must be
  390.                  * large enough for floating-point number
  391.                  * plus sign plus "E+XXX + null" */
  392.     char expBuf[CVT_INT_BUF_SIZE];
  393.                 /* Buffer to use for converting exponents. */
  394.     char *signChar;        /* This is the "+" or " " for the sign pos.  */
  395.     char *prefix;        /* Holds non-numeric stuff that precedes
  396.                  * number, such as "-" or "0x".  This is
  397.                  * kept separate to be sure we add padding
  398.                  * zeroes AFTER the prefix. */
  399.     register char *field;    /* Pointer to converted field. */
  400.     int actualLength;        /* Actual length of converted field. */
  401.     int point;            /* Location of decimal point, for "f" and
  402.                  * "e" conversions. */
  403.     int zeroPad;        /* Zeros to pad number with. */
  404.     int sign;            /* Also used for "f" and "e" conversions. */
  405.     int i, tmp;
  406.     int charsPrinted = 0;    /* Total number of characters output. */
  407.     char *end;
  408.     int fpError = FALSE;
  409.  
  410.     /*
  411.      * The main loop is to scan through the characters in format.
  412.      * Anything but a '%' is output directly to stream.  A '%'
  413.      * signals the start of a format field;  the formatting information
  414.      * is parsed, the next value from args is formatted and printed,
  415.      * and the loop goes on.
  416.      */
  417.  
  418.     for (c = *format; c != 0; format++, c = *format) {
  419.  
  420.     if (c != '%') {
  421.         putc(c, stream);
  422.         charsPrinted += 1;
  423.         continue;
  424.     }
  425.  
  426.     /*
  427.      * Parse off the format control fields.
  428.      */
  429.  
  430.     leftAdjust    = FALSE;
  431.     pad        = ' ';
  432.     minWidth    = 0;
  433.     precision    = -1;
  434.     altForm        = FALSE;
  435.     signChar    = "";
  436.     prefix        = "";
  437.     actualLength    = 0;
  438.     zeroPad        = 0;
  439.  
  440.     format++;  
  441.     c = *format;
  442.     while (TRUE) {
  443.         if (c == '-') {
  444.         leftAdjust = TRUE;
  445.         } else if (c == '0') {
  446.         pad = '0';
  447.         } else if (c == '#') {
  448.         altForm = TRUE;
  449.         } else if (c == '+') {
  450.         signChar = "+";
  451.         } else if (c== ' ') {
  452.         if (!*signChar) {
  453.             signChar = " ";
  454.         }
  455.         } else {
  456.         break;
  457.         }
  458.         format++;
  459.         c = *format;
  460.     }
  461.     if (isdigit(c)) {
  462.         minWidth = strtoul(format, &end, 10);
  463.         format = end;
  464.         c = *format;
  465.     } else if (c == '*') {
  466.         minWidth = va_arg(args, int);
  467.         format++; 
  468.         c = *format;
  469.     }
  470.     if (c == '.') {
  471.         format++; 
  472.         c = *format;
  473.         precision = 0;
  474.     }
  475.     if (isdigit(c)) {
  476.         precision = strtoul(format, &end, 10);
  477.         format = end;
  478.         c = *format;
  479.     } else if (c == '*') {
  480.         precision = va_arg(args, int);
  481.         format++; 
  482.         c = *format;
  483.     }
  484.     if (c == 'l') {            /* Ignored for compatibility. */
  485.         format++; 
  486.         c = *format;
  487.     }
  488.     if (c == 'h') {            /* Ignored for compatibility. */
  489.         format++; 
  490.         c = *format;
  491.     }
  492.  
  493.     /*
  494.      * Take action based on the format type (which is now in c).
  495.      */
  496.  
  497.     field = buf;
  498.     switch (c) {
  499.  
  500.         case 'D':
  501.         case 'd':
  502.         case 'i':
  503.         i = va_arg(args, int);
  504.         if (i < 0) {
  505.             prefix = "-";
  506.             i = -i;
  507.             actualLength = 1;
  508.         } else {
  509.             prefix = signChar;
  510.             actualLength = *prefix ? 1 : 0;
  511.         }
  512.         field = CvtUtoA((unsigned) i, 10, buf, &tmp, 0);
  513.         if (tmp < precision) {
  514.             zeroPad = precision-tmp;
  515.         }
  516.         actualLength += tmp+zeroPad;
  517.         break;
  518.         
  519.         case 'O':
  520.         case 'o':
  521.         i = va_arg(args, int);
  522.         field = CvtUtoA((unsigned) i, 8, buf, &tmp, 0);
  523.         if (tmp < precision) {
  524.             zeroPad = precision-tmp;
  525.         }
  526.         if (altForm && (i != 0) && zeroPad==0) {
  527.             prefix = "0";
  528.             actualLength = 1;
  529.         }
  530.         actualLength += tmp+zeroPad;
  531.         break;
  532.         
  533.         case 'X':
  534.         case 'x':
  535.         case 'p':
  536.         i = va_arg(args, int);
  537.         field = CvtUtoA((unsigned) i, 16, buf, &actualLength, c=='X');
  538.         if (actualLength < precision) {
  539.             zeroPad = precision-actualLength;
  540.             actualLength += zeroPad;
  541.         }
  542.         if (altForm) {
  543.             char *p;
  544.             if (c == 'X') {
  545.             if (i != 0) {
  546.                 prefix = "0X";
  547.                 actualLength += 2;
  548.             }
  549.             for (p = field; *p != 0; p++) {
  550.                 if (*p >= 'a') {
  551.                 *p += 'A' - 'a';
  552.                 }
  553.             }
  554.             } else if (i != 0) {
  555.             prefix = "0x";
  556.             actualLength += 2;
  557.             }
  558.         }
  559.         break;
  560.         
  561.         case 'U':
  562.         case 'u':
  563.         field = CvtUtoA(va_arg(args, unsigned), 10, buf,
  564.             &actualLength, 0);
  565.         if (actualLength < precision) {
  566.             zeroPad = precision-actualLength;
  567.             actualLength += zeroPad;
  568.         }
  569.         break;
  570.         
  571.         case 's':
  572.         field = va_arg(args, char *);
  573.         if (field == (char *) NULL) {
  574.             field = "(NULL)";
  575.         } 
  576.         actualLength = strlen(field);
  577.         if ((precision >= 0) && (precision < actualLength)) {
  578.             actualLength = precision;
  579.         }
  580.         pad = ' ';
  581.         break;
  582.  
  583.         case 'c':
  584.         buf[0] = va_arg(args, int);
  585.         actualLength = 1;
  586.         pad = ' ';
  587.         break;
  588.  
  589.         case 'F':
  590.         case 'f':
  591.         if (precision < 0) {
  592.             precision = 6;
  593.         } else if (precision > CVT_DBL_BUF_SIZE) {
  594.             precision = CVT_DBL_BUF_SIZE;
  595.         }
  596.  
  597.         /*
  598.          * Just generate the digits and compute the total length
  599.          * here.  The rest of the work will be done when the
  600.          * characters are actually output, below.
  601.          */
  602. #ifdef sun4
  603.          /*
  604.           * Varargs is not correctly implemented in gcc version 1.34
  605.           * for the sun4.  This problem should be fixed in the next
  606.           * version of the compiler, and this code can then be
  607.           * deleted.
  608.           */
  609.          {
  610.              union {
  611.                  long i[2];
  612.                  double d;
  613.              } u;
  614.  
  615.              u.i[0] = va_arg(args, long);
  616.              u.i[1] = va_arg(args, long);
  617.  
  618.              actualLength = CvtFtoA(u.d, CVT_DBL_BUF_SIZE,
  619.              precision, &point, &sign, field, &fpError);
  620.          }
  621. #else
  622.         actualLength = CvtFtoA(va_arg(args, double), CVT_DBL_BUF_SIZE,
  623.             precision, &point, &sign, field, &fpError);
  624. #endif
  625.         if (sign) {
  626.             prefix = "-";
  627.             actualLength += 1;
  628.         } else {
  629.             prefix = signChar;
  630.             actualLength += *prefix ? 1 : 0;
  631.         }
  632.         if (fpError) {
  633.             pad = ' ';
  634.             break;
  635.         }
  636.         if (point <= 0) {
  637.             actualLength += 1 - point;
  638.         }
  639.         if ((precision != 0) || (altForm)) {
  640.             actualLength += 1;
  641.         }
  642.         c = 'f';
  643.         break;
  644.  
  645.         case 'E':
  646.         case 'e':
  647.         if (precision < 0) {
  648.             precision = 6;
  649.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  650.             precision = CVT_DBL_BUF_SIZE-1;
  651.         }
  652. #ifdef sun4
  653.          /*
  654.           * Varargs is not correctly implemented in gcc version 1.34
  655.           * for the sun4.  This problem should be fixed in the next
  656.           * version of the compiler, and this code can then be
  657.           * deleted.
  658.           */
  659.          {
  660.              union {
  661.                  long i[2];
  662.                  double d;
  663.              } u;
  664.  
  665.              u.i[0] = va_arg(args, long);
  666.              u.i[1] = va_arg(args, long);
  667.  
  668.              actualLength = CvtFtoA(u.d, precision+1, -1,
  669.              &point, &sign, &buf[1], &fpError);
  670.          }
  671. #else
  672.         actualLength = CvtFtoA(va_arg(args, double), precision+1, -1,
  673.             &point, &sign, &buf[1], &fpError);
  674. #endif
  675.         if (fpError) {
  676.             pad = ' ';
  677.             field = &buf[1];
  678.             if (sign) {
  679.             prefix = "-";
  680.             actualLength += 1;
  681.             } else {
  682.             prefix = signChar;
  683.             actualLength += *prefix ? 1 : 0;
  684.             }
  685.             break;
  686.         }
  687.         eFromG:
  688.  
  689.         /*
  690.          * Insert a decimal point after the first digit of the number.
  691.          * If no digits after decimal point, then don't print decimal
  692.          * unless in altForm.
  693.          */
  694.  
  695.         buf[0] = buf[1];
  696.         buf[1] = '.';
  697.         if ((precision != 0) || (altForm)) {
  698.             field = buf + precision + 2;
  699.         } else {
  700.             field = &buf[1];
  701.         }
  702.  
  703.         /*
  704.          * Convert the exponent.
  705.          */
  706.         
  707.         *field = c;
  708.             field++;
  709.         point--;    /* One digit before decimal point. */
  710.         if (point < 0) {
  711.             *field = '-';
  712.             point = -point;
  713.         } else {
  714.             *field = '+';
  715.         }
  716.         field++;
  717.         if (point < 10) {
  718.             *field = '0';
  719.             field++;
  720.         }
  721.         strcpy(field, CvtUtoA((unsigned) point, 10, expBuf, &i, 0));
  722.         actualLength = (field - buf) + i;
  723.         field = buf;
  724.         if (sign) {
  725.             prefix = "-";
  726.             actualLength += 1;
  727.         } else {
  728.             prefix = signChar;
  729.             actualLength += *prefix ? 1 : 0;
  730.         }
  731.         break;
  732.  
  733.         case 'G':
  734.         case 'g': {
  735.         int eLength, fLength;
  736.  
  737.         if (precision < 0) {
  738.             precision = 6;
  739.         } else if (precision > CVT_DBL_BUF_SIZE-1) {
  740.             precision = CVT_DBL_BUF_SIZE-1;
  741.         } else if (precision == 0) {
  742.             precision = 1;
  743.         }
  744.  
  745. #ifdef sun4
  746.          /*
  747.           * Varargs is not correctly implemented in gcc version 1.34
  748.           * for the sun4.  This problem should be fixed in the next
  749.           * version of the compiler, and this code can then be
  750.           * deleted.
  751.           */
  752.          {
  753.              union {
  754.                  long i[2];
  755.                  double d;
  756.              } u;
  757.  
  758.              u.i[0] = va_arg(args, long);
  759.              u.i[1] = va_arg(args, long);
  760.  
  761.              actualLength = CvtFtoA(u.d, precision,
  762.              -1, &point, &sign, &buf[1], &fpError);
  763.          }
  764. #else
  765.         actualLength = CvtFtoA(va_arg(args, double), precision,
  766.             -1, &point, &sign, &buf[1], &fpError);
  767.  
  768. #endif
  769.         if (fpError) {
  770.             pad = ' ';
  771.             field = &buf[1];
  772.             if (sign) {
  773.             prefix = "-";
  774.             actualLength += 1;
  775.             } else {
  776.             prefix = signChar;
  777.             actualLength += *prefix ? 1 : 0;
  778.             }
  779.             break;
  780.         }
  781.         if (!altForm) {
  782.             for ( ; actualLength > 1; actualLength--) {
  783.             if (buf[actualLength] != '0') {
  784.                 break;
  785.             }
  786.             }
  787.         }
  788.         if ((actualLength > 1) || altForm) {
  789.             eLength = actualLength + 5;
  790.         } else {
  791.             eLength = actualLength + 4;
  792.         }
  793.         if (point <= 0) {
  794.             fLength = actualLength + 2 - point;
  795.         } else {
  796.             fLength = actualLength;
  797.             if (point < actualLength) {
  798.             fLength += 1;
  799.             } else if (altForm) {
  800.             fLength = point + 1;
  801.             } else {
  802.             fLength = point;
  803.             }
  804.         }
  805.  
  806.         /*
  807.          * Use "e" format if it results in fewer digits than "f"
  808.          * format, or if it would result in non-significant zeroes
  809.          * being printed.  Remember that precision means something
  810.          * different in "e" and "f" (digits after decimal) than it
  811.          * does in "g" (significant digits).
  812.          */
  813.  
  814.         if ((eLength < fLength) || (point > precision)) {
  815.             c += 'E' - 'G';
  816.             precision = actualLength-1;
  817.             goto eFromG;
  818.         }
  819.         c = 'f';
  820.         field = &buf[1];
  821.         actualLength = fLength;
  822.         if (sign) {
  823.             prefix = "-";
  824.             actualLength += 1;
  825.         } else {
  826.             prefix = signChar;
  827.             actualLength += *prefix ? 1 : 0;
  828.         }
  829.         break;
  830.         }
  831.  
  832.         case '%':
  833.         putc('%', stream);
  834.         charsPrinted += 1;
  835.         goto endOfField;
  836.  
  837.         case 0:
  838.         return charsPrinted;
  839.  
  840.         default:
  841.         putc(c, stream);
  842.         charsPrinted += 1;
  843.         goto endOfField;
  844.     }
  845.  
  846.     /*
  847.      * Things get tricky if we want to pad with 0's and left justify.
  848.      */
  849.     if (leftAdjust && pad == '0') {
  850.         if (c=='f' || c=='F' || c=='e' || c=='E' || c=='g' || c=='G') {
  851.         pad = ' ';
  852.         } else {
  853.         leftAdjust = FALSE;
  854.         }
  855.     }
  856.  
  857.     /* Handle pad characters on the left.  If the pad is '0', then
  858.      * padding goes after the prefix.  Otherwise, padding goes before
  859.      * the prefix.
  860.      */
  861.  
  862.     if (!leftAdjust) {
  863.         if (pad == '0') {
  864.         for ( ; *prefix != 0; prefix++) {
  865.             putc(*prefix, stream);
  866.             charsPrinted += 1;
  867.             actualLength--;
  868.             minWidth--;
  869.         }
  870.         }
  871.         while (minWidth > actualLength) {
  872.         putc(pad, stream);
  873.         charsPrinted += 1;
  874.         minWidth --;
  875.         }
  876.     }
  877.  
  878.     /*
  879.      * Output anything left in the prefix.
  880.      */
  881.  
  882.     minWidth -= actualLength;
  883.     for ( ; *prefix != 0; prefix++) {
  884.         putc(*prefix, stream);
  885.         charsPrinted += 1;
  886.         actualLength--;
  887.     }
  888.  
  889.     /*
  890.      * Pad the digits to the right length with 0's.
  891.      */
  892.     for (; zeroPad>0; zeroPad--) {
  893.         putc('0', stream);
  894.         charsPrinted += 1;
  895.         actualLength--;
  896.     }
  897.  
  898.     /*
  899.      * "F" and "f" formats are handled specially here:  output
  900.      * everything up to and including the decimal point.
  901.      */
  902.  
  903.     if (c == 'f' && !fpError) {
  904.         if (point <= 0) {
  905.         if (actualLength > 0) {
  906.             putc('0', stream);
  907.             charsPrinted += 1;
  908.             point++;
  909.             actualLength--;
  910.         }
  911.         if (actualLength > 0) {
  912.             charsPrinted += 1;
  913.             putc('.', stream);
  914.             actualLength--;
  915.         }
  916.         while ((point <= 0) && (actualLength > 0)) {
  917.             putc('0', stream);
  918.             charsPrinted += 1;
  919.             point++;
  920.             actualLength--;
  921.         }
  922.         } else {
  923.         while ((point > 0) && (actualLength > 0)) {
  924.             putc(*field, stream);
  925.             charsPrinted += 1;
  926.             field++;
  927.             point--;
  928.             actualLength--;
  929.         }
  930.         if (actualLength > 0) {
  931.             putc('.', stream);
  932.             charsPrinted += 1;
  933.             actualLength--;
  934.         }
  935.         }
  936.     }
  937.  
  938.     /*
  939.      * Output the contents of the field (for "f" format, this is
  940.      * just the stuff after the decimal point).
  941.      */
  942.  
  943.     charsPrinted += actualLength;
  944.     for ( ; actualLength > 0; actualLength--, field++) {
  945.         putc(*field, stream);
  946.         }
  947.  
  948.     /*
  949.      * Pad the right of the field, if necessary.
  950.      */
  951.  
  952.     while (minWidth > 0) {
  953.         putc(' ', stream);
  954.         charsPrinted += 1;
  955.         minWidth --;
  956.     }
  957.  
  958.     endOfField: continue;
  959.     }
  960.     return charsPrinted;
  961. }
  962.